/**
 * @Date: Mar 4, 2010 11:50:58 AM
 */
package com.philip.core;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import com.philip.journal.core.exception.JournalException;
import com.philip.journal.core.service.ServiceFacade;

/**
 * @author cry30
 */
public abstract class ServiceProxyHelper { // NOPMD by r39 on 3/30/11 9:17 AM

    /** Class logger. */
    //private static Logger logger = Logger.getLogger(ServiceProxyHelper.class);

    /** Stack layer index of calling method. */
    static final int IDX_METH_IN_STACK = 5;

    /** Primitive to Object type mapping. */
    private static Map<Class<?>, Class<?>> primWrapMap;
    static {
        primWrapMap = new HashMap<Class<?>, Class<?>>();
        primWrapMap.put(Integer.class, Integer.TYPE);
        primWrapMap.put(Boolean.class, Boolean.TYPE);
        primWrapMap.put(Long.class, Long.TYPE);
        primWrapMap.put(Double.class, Double.TYPE);
        primWrapMap.put(Float.class, Float.TYPE);
        primWrapMap.put(Byte.class, Byte.TYPE);
        primWrapMap.put(Short.class, Short.TYPE);
        primWrapMap.put(Character.class, Character.TYPE);
    }

    /**
     * This will delegate call to business facade passing the corresponding session data.
     *
     * @param facade Application specific facade instance.
     * @param session Session data as managed by Business session proxy.
     * @param paramType Class array of parameter types.
     * @param args arguments passed to business facade method.
     * @return result of the call to business facade.
     * @throws Exception when any exception is encountered in the call to the facade.
     */
    public static Object proxyMehodCall(final BusinessServiceFacade facade, final Map<String, Object> session,
            final Class<?>[] paramType, final Object[] args) throws Exception
    { //NOPMD
        final Map<String, Object> userSession = session;
        try {
            final Class<?>[] newTypeArr = new Class[paramType.length + 1];
            final Object[] newArgArr = new Object[paramType.length + 1];
            newTypeArr[0] = Map.class;
            newArgArr[0] = userSession;
            for (int i = 0; i < paramType.length; i++) {
                final Class<?> wrapper = primWrapMap.get(paramType[i]);
                newTypeArr[i + 1] = wrapper == null ? paramType[i] : wrapper;
                newArgArr[i + 1] = args[i];
            }

            final String methName = getCallingMethodName();
            return ServiceFacade.class.getMethod(methName, newTypeArr).invoke(facade, newArgArr);
        } catch (final InvocationTargetException ite) {
            try {
                throw (Exception) ite.getTargetException();
            } catch (final ClassCastException cce) {
                throw (RuntimeException) ite.getTargetException();
            }
        } catch (final Exception e) { // NOPMD by r39 on 4/5/11 9:10 AM
            throw new JournalException("Proxy method call exception", e);
        }
    }

    /**
     * Example of self documenting method name.
     *
     * @return calling method name.
     */
    private static String getCallingMethodName()
    {
        return Thread.currentThread().getStackTrace()[IDX_METH_IN_STACK].getMethodName();
    }
}
